package org.apache.dolphinscheduler.api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.RoleService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.dto.UserRoleListDTO;
import org.apache.dolphinscheduler.dao.entity.Permission;
import org.apache.dolphinscheduler.dao.entity.Role;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.entity.UserRole;
import org.apache.dolphinscheduler.dao.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author
 * @date 2023-07-03 09:52
 * @descriprion
 */
@Service
@Slf4j
public class RoleServiceImpl extends BaseServiceImpl implements RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private PermissionMapper permissionMapper;

    @Override
    public Result queryRoleList(User loginUser, String searchVal, Integer pageNo, Integer pageSize) {
        Result result = new Result();
//        if (!isAdmin(loginUser)) {
//            putMsg(result, Status.USER_NO_OPERATION_PERM);
//            return result;
//        }
        Page<Role> page = new Page<>(pageNo, pageSize);
        IPage<Role> list = roleMapper.queryRolePage(page, searchVal);
        PageInfo<Role> pageInfo = new PageInfo<>(pageNo, pageSize);
        pageInfo.setTotal((int) list.getTotal());
        pageInfo.setTotalList(list.getRecords());
        result.setData(pageInfo);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result listAll() {
        Result result = new Result();
        List<Role> list = roleMapper.listAll();
        result.setData(list);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result findRoleUser(Integer id) {
        Result result = new Result();
        List<UserRoleListDTO> list = userRoleMapper.selectRoleUser(id);
        result.setData(list);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result findRole(Integer id) {
        Result result = new Result();
        Role role = roleMapper.selectById(id);
        result.setData(role);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Result getPermissions(Integer id) {
        Result result = new Result();
        if (id.intValue() == 1) {
            List<Permission> list = permissionMapper.listAll();
            result.setData(build(list));
        } else {
            List<Permission> list = permissionMapper.listByRoleId(id);
            result.setData(build(list));
        }
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Map<String, Object> auth(User loginUser, Integer roleId, List<Integer> permissionIds) {
        Map<String, Object> result = new HashMap<>();
        if (roleId == null) {
            putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, "角色ID");
            return result;
        }
        // if (permissionIds==null || permissionIds.size()==0) {
        // putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, "权限ID列表");
        // return result;
        // }
        if (!isAdmin(loginUser)) {
            putMsg(result, Status.USER_NO_OPERATION_PERM);
            return result;
        }
        rolePermissionMapper.deleteByRoleId(roleId);
        if (permissionIds != null && permissionIds.size() > 0) {
            rolePermissionMapper.insert(roleId, permissionIds);
        }

        Role role = roleMapper.selectById(roleId);
        role.setUpdateTime(new Date());
        role.setId(roleId);
        roleMapper.update(role);

        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    @Transactional
    public Map<String, Object> createRole(User loginUser, Role role) {
        Map<String, Object> result = new HashMap<>();
        // check all user params
        String msg = this.checkParams(role);

        if (!StringUtils.isEmpty(msg)) {
            putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, msg);
            return result;
        }

        if (roleMapper.selectByRoleName(role.getRoleName()) != null) {
            putMsg(result, Status.ROLE_NAME_EXIST, msg);
            return result;
        }
        if (!isAdmin(loginUser)) {
            putMsg(result, Status.USER_NO_OPERATION_PERM);
            return result;
        }
        Date now = DateUtils.getCurrentDate();
        role.setCreateUser(loginUser.getUserName());
        role.setCreateTime(now);
        role.setUpdateTime(now);
        int f = roleMapper.insert(role);
        if (f <= 0) {
            putMsg(result, Status.CREATE_ROLE_ERROR, msg);
            return result;
        }
        // 默认添加首页权限
        List<Integer> permissionIds = permissionMapper.listByPermission("home:list");
        if (role.getId() != null && permissionIds != null && permissionIds.size() > 0) {
            rolePermissionMapper.insert(role.getId(), permissionIds);
        }
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Map<String, Object> updateRole(User loginUser, Role role) {
        Map<String, Object> result = new HashMap<>();
        // check all user params
        String msg = this.checkParams(role);
        if (!StringUtils.isEmpty(msg)) {
            putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, msg);
            return result;
        }
        // check role exists
        Role current = roleMapper.selectById(role.getId());
        if (current == null) {
            putMsg(result, Status.ROLE_NOT_EXIST, msg);
            return result;
        }
        Role roleName = roleMapper.selectByRoleName(role.getRoleName());
        if (roleName != null && !roleName.getId().equals(role.getId())) {
            putMsg(result, Status.ROLE_NAME_EXIST, msg);
            return result;
        }

        // check user permission
        if (!isAdmin(loginUser)) {
            putMsg(result, Status.USER_NO_OPERATION_PERM);
            return result;
        }
        role.setCreateUser(loginUser.getUserName());

        if (current.getTenantId() != role.getTenantId()) {
            userMapper.updateTenantId(role.getId(), role.getTenantId());
        }
        role.setUpdateTime(DateUtils.getCurrentDate());
        roleMapper.update(role);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    @Transactional
    public Map<String, Object> deleteRole(User loginUser, Integer id) {
        Map<String, Object> result = new HashMap<>();
        if (id == null || id.intValue() <= 0) {
            putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, "角色ID");
            return result;
        }
        if (id.intValue() == 1) {
            putMsg(result, Status.ROLE_IS_ADMIN);
            return result;
        }
        if (!isAdmin(loginUser)) {
            putMsg(result, Status.USER_NO_OPERATION_PERM);
            return result;
        }
        boolean flag = getCountRoleUser(id);
        if(flag) {
        	putMsg(result, Status.ROLE_HAS_USER);
            return result;
        }
        // 删除角色
        roleMapper.delete(id);
        // 删除角色权限关联
        rolePermissionMapper.deleteByRoleId(id);
        // 删除角色用户关联
        userRoleMapper.deleteByRoleId(id);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Map<String, Object> updateRoleUser(User loginUser, String userIds, Integer roleId) {
        Map<String, Object> result = new HashMap<>();
        result.put(Constants.STATUS, false);

        // check exist
        Role tempRole = roleMapper.selectById(roleId);
        if (tempRole == null) {
            log.error("Role does not exist, roleId:{}.", roleId);
            putMsg(result, Status.ROLE_NOT_EXIST, roleId);
            return result;
        }

        if (check(result, StringUtils.isEmpty(userIds), Status.SUCCESS)) {
            log.warn("Parameter userIds is empty.");
            return result;
        }
        Arrays.stream(userIds.split(",")).distinct().forEach(userId -> {
            userRoleMapper.deleteByUserId(Integer.parseInt(userId));
            UserRole userRole = new UserRole();
            userRole.setUserId(Integer.parseInt(userId));
            userRole.setRoleId(roleId);
            userRoleMapper.insert(userRole);
        });
        putMsg(result, Status.SUCCESS);
        return result;
    }

    private String checkParams(Role role) {
        if (StringUtils.isBlank(role.getRoleName())) {
            return "角色名称";
        }
        if (StringUtils.isBlank(role.getRoleComment())) {
            return "角色描述";
        }
        if (role.getTenantId() == null) {
            return "所属租户";
        }
        return null;
    }

    private List<Permission> build(List<Permission> list) {
        List<Permission> res = new ArrayList<>();
        for (Permission node : list) {
            // 如果是父节点，就查找下面所有字节点添加到子节点的集合中，也可以先把所有一级节点过滤出来遍历
            if (node.getParentId() == null || node.getParentId().intValue() == 0) {
                buildChildren(node, list);
                res.add(node);
            }
        }
        return res;
    }

    /**
     *  递归查找一个节点下的所有子节点
     * @param node
     * @param list
     */
    private void buildChildren(Permission node, List<Permission> list) {
        // 将所有的一级子节点查询出来
        List<Permission> children =
                list.stream().filter(p -> (p.getParentId() != null && p.getParentId().equals(node.getId())))
                        .collect(Collectors.toList());
        // 如果一级子节点不为空，开始递归查找所有节点，直到子节点集合为空停止
        if (!CollectionUtils.isEmpty(children)) {
            for (Permission n : children) {
                buildChildren(n, list);
            }
            node.setChildren(children);
        }
    }
    
    private boolean getCountRoleUser(Integer roleId) {
    	List<Integer> list = userRoleMapper.selectRoleUserIds(roleId);
    	if(list != null && list.size() > 0) {
    		return true;
    	} else {
    		return false;
    	}
    }
}
